﻿using Abp;
using Abp.AutoMapper;
using Abp.Domain.Repositories;
using Abp.ObjectMapping;
using AutoMapper.QueryableExtensions;
using FwProject.Core.SettlementInfoModel;
using FwProject.PrePaymentInfo;
using FwProject.Restaurant;
using FwProject.Settlement.Dto;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using X.PagedList;
using Microsoft.EntityFrameworkCore.DynamicLinq;
using System.Linq.Dynamic.Core;
using Abp.UI;

namespace FwProject.Settlement
{
    /// <summary>
    /// 账户管理
    /// </summary>
    public class SettlementAccountAppService : FwProjectAppServiceBase, ISettlementAccountAppService
    {
        public readonly IRepository<SettlementAccount, Guid> _repositorySettlementAccount;
        public readonly IRepository<ReceiptInfoModel, Guid> _repositoryReceiptInfo;
        public readonly IRepository<DepositInfo, Guid> _repositoryDepositInfo;
        public readonly IRepository<PrePaymentInfoModel, Guid> _repositoryPrePaymentInfo;
        public IGuidGenerator _guid { get; set; }
        public IObjectMapper _map { get; set; }

        public SettlementAccountAppService(IRepository<SettlementAccount, Guid> repositorySettlementAccount, IRepository<ReceiptInfoModel, Guid> repositoryReceiptInfo,
            IRepository<DepositInfo, Guid> repositoryDepositInfo, IRepository<PrePaymentInfoModel, Guid> repositoryPrePaymentInfo)
        {
            _repositorySettlementAccount = repositorySettlementAccount;
            _guid = SequentialGuidGenerator.Instance;
            _repositoryReceiptInfo = repositoryReceiptInfo;
            _repositoryDepositInfo = repositoryDepositInfo;
            _repositoryPrePaymentInfo = repositoryPrePaymentInfo;
        }

        public async Task<SettlementAccountOutputDto> GetByIdAsync(Guid id)
        {
            var model = await _repositorySettlementAccount.GetAsync(id);
            return _map.Map<SettlementAccountOutputDto>(model);
        }
        /// <summary>
        /// 获取所有账户
        /// </summary>
        /// <returns></returns>
        public async Task<List<SettlementAccountOutputDto>> GetAllSettlementAccountAsync()
        {
            var user = await base.GetCurrentUserAsync();
            var query = _repositorySettlementAccount.GetAll().Where(o => o.FactoryinfoId == user.FactoryinfoId);

            return await query.OrderByDescending(m => m.CreationTime).ProjectTo<SettlementAccountOutputDto>().ToListAsync();
        }

        public async Task<IPagedList<SettlementAccountOutputDto>> GetPagedListAsync(int pageIdx, int pageSize, string keyword)
        {
            var user = await base.GetCurrentUserAsync();
            var query = _repositorySettlementAccount.GetAll().Where(o => o.FactoryinfoId == user.FactoryinfoId);
            if (!string.IsNullOrEmpty(keyword))
                query = query.Where(o => o.Name.Contains(keyword) || o.Number.Contains(keyword));

            return await query.OrderByDescending(m => m.CreationTime).ProjectTo<SettlementAccountOutputDto>().ToPagedListAsync(pageIdx, pageSize);
        }
        /// <summary>
        /// 获取一个账户信息
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<SettlementAccountEnterDto> GetEnterDto(Guid id)
        {
            var entity = await _repositorySettlementAccount.GetAsync(id);
            return entity.MapTo<SettlementAccountEnterDto>();
        }
        /// <summary>
        /// 创建一个账户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<Guid> CreateAsync(SettlementAccountEnterDto input)
        {
            var user = await base.GetCurrentUserAsync();
            var model = input.MapTo<SettlementAccount>();
            model.Id = _guid.Create();
            model.FactoryinfoId = user.FactoryinfoId.Value;
            return await _repositorySettlementAccount.InsertAndGetIdAsync(model);
        }
        /// <summary>
        /// 修改一个账户信息
        /// </summary>
        /// <param name="id"></param>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task ModifyAsync(Guid id, SettlementAccountEnterDto input)
        {
            var model = await _repositorySettlementAccount.GetAsync(id);
            input.MapTo(model);
            await _repositorySettlementAccount.UpdateAsync(model);
        }

        public async Task DeleteAsync(Guid id)
        {
            await _repositorySettlementAccount.DeleteAsync(id);
        }
        /// <summary>
        /// 获取资金池数据
        /// </summary>
        /// <param name="Date"></param>
        /// <returns></returns>
        public async Task<List<CapitalPoolDto>> GetCapitalPoolListAsync(DateTime? date)
        {
            if (date.Value == null)
                throw new UserFriendlyException("请输入查询日期！");
            var factoryid = (await base.GetCurrentUserAsync()).FactoryinfoId;
            var account = _repositorySettlementAccount.GetAll();
            var receipt = _repositoryReceiptInfo.GetAll().Where(o => o.FactoryinfoId == factoryid);
            var collectDeposit = _repositoryDepositInfo.GetAll().Where(o => o.FactoryinfoId == factoryid && o.DepositType == DepositType.收押金);
            var collectPrePayment = _repositoryPrePaymentInfo.GetAll().Where(o => o.FactoryinfoId == factoryid && o.PrePaymentInfoType == PrePaymentInfoType.收预交金);
            var returnDeposit = _repositoryDepositInfo.GetAll().Where(o => o.FactoryinfoId == factoryid && o.DepositType == DepositType.退押金);
            var returnPrePayment = _repositoryPrePaymentInfo.GetAll().Where(o => o.FactoryinfoId == factoryid && o.PrePaymentInfoType == PrePaymentInfoType.退预交金);

            var d = account.GroupJoin(receipt.Where(o => o.CreationTime.Date <= date.Value.Date), a => a.Id, b => b.CapitalAccountId, (a, b) => new
            {
                a.Id,
                a.Name,
                a.InitialAmount,
                ReceiptMoney = b.Sum(s => s.TaskBackAmount)
            }).GroupJoin(collectDeposit.Where(o => o.DepositTime.Date <= date.Value.Date), a => a.Id, b => b.CapitalAccountId, (a, b) => new
            {
                a.Name,
                a.Id,
                a.InitialAmount,
                Money = a.ReceiptMoney + b.Sum(s => s.Money),
            }).GroupJoin(collectPrePayment.Where(o => o.CreationTime.Date <= date.Value.Date), a => a.Id, b => b.CapitalAccountId, (a, b) => new
            {
                a.Id,
                a.Name,
                a.InitialAmount,
                Money = a.Money + b.Sum(s => s.PrePaymentPrice)
            }).GroupJoin(returnDeposit.Where(o => o.DepositTime.Date <= date.Value.Date), a => a.Id, b => b.CapitalAccountId, (a, b) => new
            {
                a.Id,
                a.Name,
                a.InitialAmount,
                Income = a.Money,
                ReturnDeposit = b.Sum(s => s.Money)
            }).GroupJoin(returnPrePayment.Where(o => o.CreationTime.Date <= date.Value.Date), a => a.Id, b => b.CapitalAccountId, (a, b) => new
            {
                a.Id,
                a.Name,
                a.InitialAmount,
                a.Income,
                Expenditure = a.ReturnDeposit + b.Sum(s => s.PrePaymentPrice)
            }).Select(s => new CapitalPoolDto
            {
                AccountId = s.Id,
                Balance = s.InitialAmount + s.Income - s.Expenditure
            });

            //var d = account.GroupJoin(receipt.Where(o=>o.CreationTime<=date.Value.AddHours(24)), a => a.Id, b => b.CapitalAccountId, (a, b) => new
            //{
            //    a.Id,
            //    a.Name,
            //    a.InitialAmount,
            //    ReceiptMoney = b.Sum(s => s.TaskBackAmount)
            //}).GroupJoin(collectDeposit.Where(o => o.DepositTime <= date.Value.AddHours(24)), a => a.Id, b => b.CapitalAccountId, (a, b) => new
            //{
            //    a.Name,
            //    a.Id,
            //    a.InitialAmount,
            //    Money = a.ReceiptMoney + b.Sum(s => s.Money),
            //}).GroupJoin(collectPrePayment.Where(o => o.CreationTime <= date.Value.AddHours(24)), a => a.Id, b => b.CapitalAccountId, (a, b) => new
            //{
            //    a.Id,
            //    a.Name,
            //    a.InitialAmount,
            //    Money = a.Money + b.Sum(s => s.PrePaymentPrice)
            //}).GroupJoin(returnDeposit.Where(o => o.DepositTime <= date.Value.AddHours(24)), a => a.Id, b => b.CapitalAccountId, (a, b) => new
            //{
            //    a.Id,
            //    a.Name,
            //    a.InitialAmount,
            //    Income = a.Money,
            //    ReturnDeposit = b.Sum(s => s.Money)
            //}).GroupJoin(returnPrePayment.Where(o => o.CreationTime <= date.Value.AddHours(24)), a => a.Id, b => b.CapitalAccountId, (a, b) => new
            //{
            //    a.Id,
            //    a.Name,
            //    a.InitialAmount,
            //    a.Income,
            //    Expenditure = a.ReturnDeposit + b.Sum(s => s.PrePaymentPrice)
            //}).Select(s => new CapitalPoolDto
            //{
            //    AccountId = s.Id,
            //    Balance = s.InitialAmount + s.Income - s.Expenditure
            //});


            if (date.HasValue)
            {
                receipt = receipt.Where(o => EF.Functions.DateDiffDay(o.CreationTime, date) == 0);
                collectDeposit = collectDeposit.Where(o => EF.Functions.DateDiffDay(o.DepositTime, date) == 0);
                collectPrePayment = collectPrePayment.Where(o => EF.Functions.DateDiffDay(o.CreationTime, date) == 0);
                returnDeposit = returnDeposit.Where(o => EF.Functions.DateDiffDay(o.DepositTime, date) == 0);
                returnPrePayment = returnPrePayment.Where(o => EF.Functions.DateDiffDay(o.CreationTime, date) == 0);
            }
            else
            {
                receipt = receipt.Where(o => EF.Functions.DateDiffDay(o.CreationTime, DateTime.Now) == 0);
                collectDeposit = collectDeposit.Where(o => EF.Functions.DateDiffDay(o.DepositTime, DateTime.Now) == 0);
                collectPrePayment = collectPrePayment.Where(o => EF.Functions.DateDiffDay(o.CreationTime, DateTime.Now) == 0);
                returnDeposit = returnDeposit.Where(o => EF.Functions.DateDiffDay(o.DepositTime, DateTime.Now) == 0);
                returnPrePayment = returnPrePayment.Where(o => EF.Functions.DateDiffDay(o.CreationTime, DateTime.Now) == 0);
            }

            //var receipt = _repositoryReceiptInfo.GetAll().Where(o =>o.FactoryinfoId==factoryid && EF.Functions.DateDiffDay(o.CreationTime, DateTime.Now) == 0);
            //var collectDeposit = _repositoryDepositInfo.GetAll().Where(o => o.FactoryinfoId == factoryid && EF.Functions.DateDiffDay(o.CreationTime, DateTime.Now) == 0 && o.DepositType == DepositType.收押金);
            //var collectPrePayment = _repositoryPrePaymentInfo.GetAll().Where(o => o.FactoryinfoId == factoryid && EF.Functions.DateDiffDay(o.CreationTime, DateTime.Now) == 0 && o.PrePaymentInfoType == PrePaymentInfoType.收预交金);
            //var returnDeposit = _repositoryDepositInfo.GetAll().Where(o => o.FactoryinfoId == factoryid && EF.Functions.DateDiffDay(o.CreationTime, DateTime.Now) == 0 && o.DepositType == DepositType.退押金);
            //var returnPrePayment = _repositoryPrePaymentInfo.GetAll().Where(o => o.FactoryinfoId == factoryid && EF.Functions.DateDiffDay(o.CreationTime, DateTime.Now) == 0 && o.PrePaymentInfoType == PrePaymentInfoType.退预交金);

            var data = account.GroupJoin(receipt, a => a.Id, b => b.CapitalAccountId, (a, b) => new
            {
                a.Id,
                a.Name,
                a.InitialAmount,
                ReceiptMoney = b.Sum(s => s.TaskBackAmount)
            }).GroupJoin(collectDeposit, a => a.Id, b => b.CapitalAccountId, (a, b) => new
            {
                a.Name,
                a.Id,
                a.InitialAmount,
                Money = a.ReceiptMoney + Convert.ToDecimal(b.Sum(s => s.Money)),
            }).GroupJoin(collectPrePayment, a => a.Id, b => b.CapitalAccountId, (a, b) => new
            {
                a.Id,
                a.Name,
                a.InitialAmount,
                Money = a.Money + b.Sum(s => s.PrePaymentPrice)
            }).GroupJoin(returnDeposit, a => a.Id, b => b.CapitalAccountId, (a, b) => new
            {
                a.Id,
                a.Name,
                a.InitialAmount,
                DailyIncome = a.Money,
                ReturnDeposit = Convert.ToDecimal(b.Sum(s => s.Money))
            }).GroupJoin(returnPrePayment, a => a.Id, b => b.CapitalAccountId, (a, b) => new
            {
                a.Id,
                a.Name,
                a.InitialAmount,
                a.DailyIncome,
                DailyExpenditure = a.ReturnDeposit + b.Sum(s => s.PrePaymentPrice)
            }).Join(d, a => a.Id, b => b.AccountId, (a, b) => new CapitalPoolDto
            {
                AccountId = a.Id,
                AccountName = a.Name,
                DailyIncome = a.DailyIncome,
                DailyExpenditure = a.DailyExpenditure,
                Balance = b.Balance
            });

            return data.ToList();
        }
    }
}
